/*
 * @Author: GT<caogtaa@gmail.com>
 * @Date: 2020-12-28 15:39:39
 * @LastEditors: GT<caogtaa@gmail.com>
 * @LastEditTime: 2021-03-21 01:34:41
 */

var path = require('path');
var fs = require('fs');

function onBeforeBuildFinish (options, callback) {
    // Editor.log('Building ' + options.platform + ' to ' + options.dest); // 你可以在控制台输出点什么

    // var mainJsPath = path.join(options.dest, 'main.js');  // 获取发布目录下的 main.js 所在路径
    // var script = fs.readFileSync(mainJsPath, 'utf8');     // 读取构建好的 main.js
    // script += '\n' + 'window.myID = "01234567";';         // 添加一点脚本到
    // fs.writeFileSync(mainJsPath, script);                 // 保存 main.js

    callback();
}

function onBuildFinished (options, callback) {
    if (options.debug) {
        Editor.log('[ENGINE-SPLITER]', '调试模式跳过优化');
        callback();
        return;
    }

    Editor.log('Build finished ' + options.platform + ' to ' + options.dest); // 你可以在控制台输出点什么

    // var mainJsPath = path.join(options.dest, 'main.js');  // 获取发布目录下的 main.js 所在路径
    // var script = fs.readFileSync(mainJsPath, 'utf8');     // 读取构建好的 main.js
    // script += '\n' + 'window.myID = "01234567";';         // 添加一点脚本到
    // fs.writeFileSync(mainJsPath, script);                 // 保存 main.js

    if (options.platform === "mini-game") {
        doSplit();
    }

    callback();
}

/**
 * 遍历文件/文件夹并执行函数
 * @param {Fs.PathLike} path 路径
 * @param {(filePath: Fs.PathLike, stat: Fs.Stats)=>void} handler 处理函数
 */
function traverseDir(dir, handler) {
    if (!fs.existsSync(dir))
        return;

    const stats = fs.statSync(dir);
    if (stats.isDirectory()) {
        if (!handler(dir, stats)) {
            // do not traverse this dir, maybe removed in handler
            return;
        }

        const names = fs.readdirSync(dir);
        for (const name of names) {
            traverseDir(path.join(dir, name), handler);
        }
    } else if (stats.isFile()) {
        handler(dir, stats);
    }
}

function copyFileSync( source, target ) {

    var targetFile = target;

    // If target is a directory, a new file with the same name will be created
    if ( fs.existsSync( target ) ) {
        if ( fs.lstatSync( target ).isDirectory() ) {
            targetFile = path.join( target, path.basename( source ) );
        }
    }

    fs.writeFileSync(targetFile, fs.readFileSync(source));
}

function copyFolderRecursiveSync( source, target ) {
    var files = [];

    // Check if folder needs to be created or integrated
    var targetFolder = path.join( target, path.basename( source ) );
    if ( !fs.existsSync( targetFolder ) ) {
        fs.mkdirSync( targetFolder );
    }

    // Copy
    if ( fs.lstatSync( source ).isDirectory() ) {
        files = fs.readdirSync( source );
        files.forEach( function ( file ) {
            var curSource = path.join( source, file );
            if ( fs.lstatSync( curSource ).isDirectory() ) {
                copyFolderRecursiveSync( curSource, targetFolder );
            } else {
                copyFileSync( curSource, targetFolder );
            }
        } );
    }
}

function deleteFolderRecursive(dir) {
    if (fs.existsSync(dir)) {
        fs.readdirSync(dir).forEach((file, index) => {
            const curPath = path.join(dir, file);
            if (fs.lstatSync(curPath).isDirectory()) { // recurse
                deleteFolderRecursive(curPath);
            } else { // delete file
                fs.unlinkSync(curPath);
            }
        });
    }

    fs.rmdirSync(dir);
}

function doSplit() {
    Editor.log('[ENGINE-SPLITER]', '开始拆分小游戏引擎');

    let destPath = path.join(Editor.Project.path, 'projects', 'wechatgame');
    Editor.log('[ENGINE-SPLITER]', destPath);

    // move engine files to engine/ folder
    let engineDir = path.join(destPath, 'engine');
    let files = ['adapter-min.js', 'ccRequire.js', 'game.js', 'main.js', 'cocos', 'src', 'adapter.js'/*debug mode*/];
    for (let f of files) {
        let from = path.join(destPath, f);
        let to = path.join(engineDir, f);
        if (fs.existsSync(from)) {
            Editor.log('[ENGINE-SPLITER]', 'move ', from, 'to', to);
            fs.renameSync(from, to);
        }
    }

    // copy asset into engine/ folder
    let mainAssetsDir = path.join(destPath, 'assets')
    let engineAssetsDir = path.join(engineDir, 'assets');
    {
        let from = mainAssetsDir;
        let to = engineDir;// engineAssetsDir; 拷贝到父目录
        if (fs.existsSync(from)) {
            Editor.log('[ENGINE-SPLITER]', 'copy ', from, 'to', to);
            copyFolderRecursiveSync(from, to);
        }
    }

    // remove all index.js/index.js.map in main asset
    traverseDir(mainAssetsDir, (filePath, stats) => {
        if (path.basename(filePath).startsWith('index.js')) {
            Editor.log('[ENGINE-SPLITER]', 'remove ', filePath);
            fs.unlinkSync(filePath);
        }

        return true;
    });
    
    // remove all resources in engine asset
    traverseDir(engineAssetsDir, (filePath, stats) => {
        let baseName = path.basename(filePath);
        if (baseName === 'import' || baseName == 'native' || baseName.startsWith('config.')) {
            if (stats.isDirectory()) {
                Editor.log('[ENGINE-SPLITER]', 'remove dir', filePath);
                deleteFolderRecursive(filePath);
            } else {
                Editor.log('[ENGINE-SPLITER]', 'remove file', filePath);
                fs.unlinkSync(filePath);
            }

            return false;
        }

        return true;
    });

    // rename game-backup.js to game.js
    {
        let from = path.join(destPath, 'game-backup.js');
        let to = path.join(destPath, 'game.js');
        if (fs.existsSync(from)) {
            Editor.log('[ENGINE-SPLITER]', 'move ', from, 'to', to);
            fs.renameSync(from, to);
        }
    }

    // write engine folder into game.json
    Editor.log('[ENGINE-SPLITER]', 'update game.json');
    let gameJsonFilePath = path.join(destPath, 'game.json');
    let gameJson = JSON.parse(fs.readFileSync(gameJsonFilePath, 'utf8'));
    let subpackages = gameJson['subpackages'];
    subpackages.splice(0, 0, {
        name: "engine",
        root: "engine/"
    });

    // project hardcode, remove some package not for release
    // let useless = ["mapBackup", "editor"];
    let useless = ["mapBackup"];
    for (let n = subpackages.length, i=n-1; i >= 0; --i) {
        let p = subpackages[i];
        if (useless.indexOf(p["name"]) >= 0) {
            subpackages.splice(i, 1);
            Editor.log('[ENGINE-SPLITER]', 'remove subpackage ', p["name"]);
        }
    }
    
    fs.writeFileSync(gameJsonFilePath, JSON.stringify(gameJson, null, 4));
    Editor.log('[ENGINE-SPLITER]', 'update game.json finish');
}

module.exports = {
    messages: {
        'split' () {
            doSplit();
        }
    },

    load () {
        Editor.Builder.on('before-change-files', onBeforeBuildFinish);
        Editor.Builder.on('build-finished', onBuildFinished);
    },

    unload () {
        Editor.Builder.removeListener('before-change-files', onBeforeBuildFinish);
        Editor.Builder.removeListener('build-finished', onBuildFinished);
    }
};